local oo = require("SharedLibs.BaseLib");
local co = require("SharedLibs.CoroLib");

Debugger = require("SharedLibs.Debugger");
TimerMgr = require("SharedLibs.TimerMgr");

AsyncOp = require("SharedLibs.AsyncOp");
AsyncOpState = require("SharedLibs.AsyncOpState");

_IsStudio = Debugger.IsStudio;

--- WaitTime Class ---
co.WaitTime = oo.Class();
local WaitTime = co.WaitTime;
WaitTime.name = "WaitTime";
oo.ClassExtends(WaitTime, AsyncOp);

--- -1代表等待一帧, 0代表无等待（会同步执行到后续代码）
function co.Delay(seconds)
	local op = oo.New(WaitTime, seconds or -1);
	return co.yield(op);
end

--- -1代表等待一帧, 0代表无等待（会同步执行到后续代码）
function co.NewDelay(seconds) 
	return oo.New(WaitTime, seconds or -1);
end


--- 为了减少GC, 给每个Coro对象缓存一个WaitTime象用来专门做WaitFrame， 
assert(co._WaitFrame == nil);
co._WaitFrame = nil;

function co.WaitFrame()
	local coro = co.GetCurrent();
	if coro == nil then 
		--- 不能直接返回! 否则会引发Selector里调用waitFrame死循环
		--- 所有类似WaitFrame的需要使用per coro缓存的Op, 当coro为nil时都应该coroutine.yield(nil)!!!
		coroutine.yield(nil);
	else
		local op = coro._WaitFrame; 
		if op == nil then 
			--- -1代表等待一帧
			op = oo.New(WaitTime, -1);
			coro._WaitFrame = op;
		else
			op:Reset();
		end
		return co.yield(op);
	end	
end

----
function WaitTime.prototype:constructor(seconds)
	WaitTime._ss.prototype.constructor(self)
	self._state = AsyncOpState.Ready
	if _IsStudio then
		assert(type(seconds) == "number");
	end
	self._interval = seconds;
	
	self._startTime = 0;
	self._pausedTime = 0;
	
	--- Implements ITickable
	self.isInQueue = false;
	self.isStopped = false;
end

function WaitTime.prototype:Update()
	if self._state ~= AsyncOpState.Executing then return end;

	local fElapsedTime = TimerMgr.currentTime - self._startTime;
	if fElapsedTime >= self._interval then
		self:_doStop(true);
	end;
end

function WaitTime.prototype:_onStart()
	if self._interval == 0 then
		self:_doStop(true);
	else
		--- Cannot use TimerMgr.SetTimer, because it doesn't support pause/resume. 
		TimerMgr.Enqueue(self);	
		self._startTime = TimerMgr.currentTime;	
	end	
end

function WaitTime.prototype:_onStop()
	self.isStopped = true;
end

function WaitTime.prototype:_onReset()
	self.isStopped = false;
end

function WaitTime.prototype:Stop()
	if (AsyncOpState.Ready == self._state) or (AsyncOpState.Stopped == self._state) then
		return
	end

	self._state = AsyncOpState.Stopped
	self._continuation = nil	

	self._startTime = 0;	
	self.isStopped = true;
end

function WaitTime.prototype:Pause()
	if AsyncOpState.Paused == self._state
		or AsyncOpState.Ready == self._state 
		or AsyncOpState.Stopped == self._state then
		return
	end
	self._state = AsyncOpState.Paused
	self._pausedTime = TimerMgr.currentTime;
end

function WaitTime.prototype:Resume()
	if AsyncOpState.Ready == self._state
		or AsyncOpState.Stopped == self._state 
		or AsyncOpState.Executing == self._state then
		return
	end
	self._state = AsyncOpState.Executing
	self._startTime = self._startTime + (TimerMgr.currentTime - self._pausedTime);
	self._pausedTime = 0;
end

function WaitTime.prototype:GetReturn()
	return self._interval;
end

return WaitTime;
